package com.xw.unification.handler;

import com.xw.unification.annotations.ApiVersion;
import com.xw.unification.config.WebUnificationMvcProperties.ApiVersionProperties;
import com.xw.unification.entity.ApiVersionCondition;
import com.xw.unification.utils.AnnotationDetector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * API 请求路径版本号处理映射器
 *
 * @author qiwei
 * @date 2023-8-9 21:00:00
 * @since v1.0.0
 */
public class PathVersionHandlerMapping extends RequestMappingHandlerMapping {

    private ApiVersionProperties properties;

    private final List<ApiVersionCondition> conditionList = new LinkedList<>();

    public PathVersionHandlerMapping(ApiVersionProperties apiVersionProperties) {
        this.properties = apiVersionProperties;
    }

    @Override
    protected boolean isHandler(Class<?> beanType) {
        return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
    }

    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ApiVersion apiVersion = AnnotationDetector.findAnnotation(handlerType, ApiVersion.class);
        return createTypeCondition(handlerType, apiVersion);
    }

    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationDetector.findAnnotation(method,ApiVersion.class);
        return createMethodCondition(method, apiVersion);
    }

    private RequestCondition<ApiVersionCondition>createTypeCondition(Class<?> handlerType, ApiVersion apiVersion) {
        if (apiVersion == null) {
            return null;
        } else {
            ApiVersionCondition condition = new ApiVersionCondition(this, handlerType, apiVersion, properties);
            addCondition(condition);
            return condition;
        }
    }

    private RequestCondition<ApiVersionCondition>createMethodCondition(Method method, ApiVersion apiVersion) {
        if (apiVersion == null) {
            return null;
        } else {
            ApiVersionCondition condition = new ApiVersionCondition(this, method, apiVersion, properties);
            addCondition(condition);
            return condition;
        }
    }

    void addCondition(ApiVersionCondition condition) {
        if (condition != null) {
            synchronized (conditionList) {
                conditionList.add(condition);
            }
        }
    }

    public void removeCondition(ApiVersionCondition condition) {
        if (condition != null) {
            synchronized (conditionList) {
                conditionList.remove(condition);
            }
        }
    }

}
